package com.drore.logapp.http.token;

import android.content.Intent;
import android.text.TextUtils;
import android.util.Log;

import com.drore.app.utils.LogUtils;
import com.drore.logapp.base.BaseApplication;
import com.drore.logapp.bean.BaseBean;
import com.drore.logapp.http.HttpTokenLogin;
import com.drore.logapp.utils.SPUtil;
import com.drore.logapp.utils.SpKeyUtils;
import com.google.gson.Gson;

import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.nio.charset.Charset;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import okhttp3.MediaType;
import okhttp3.RequestBody;
import okio.Buffer;
import retrofit2.http.Body;
import retrofit2.http.Query;
import rx.Observable;
import rx.Subscriber;
import rx.functions.Func1;

/**
 * 代理
 * Created by YaNan on 2017/3/24 0024.
 */

public class ProxyHandler implements InvocationHandler {

    private final static String TAG = "ProxyHandler";
    private final static String TOKEN = "token";
    private final static int REFRESH_TOKEN_VALID_TIME = 30;
    private static long tokenChangedTime;
    private Throwable mRefreshTokenError = null;
    private boolean mIsTokenNeedRefresh;
    private Object mProxyObject;
    private int refresh = 0;

    public ProxyHandler(Object proxyObject) {
        mProxyObject = proxyObject;
    }

    @Override
    public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable {
        return Observable.just(null).flatMap(new Func1<Object, Observable<?>>() {

            @Override
            public Observable<?> call(Object o) {
                try {
                    try {
                        if (mIsTokenNeedRefresh) {
                            updateMethodToken(method, args);
                        }
                        return (Observable<?>) method.invoke(mProxyObject, args);
                    } catch (InvocationTargetException e) {
                        LogUtils.e(TAG, "构建请求失败，请检查请求方式，参数是否正确。\n" + e.toString());
                        e.printStackTrace();
                    }
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
                return null;
            }
        }).retryWhen(new Func1<Observable<? extends Throwable>, Observable<?>>() {

            @Override
            public Observable<?> call(Observable<? extends Throwable> observable) {
                return observable.flatMap(new Func1<Throwable, Observable<?>>() {

                    @Override
                    public Observable<?> call(Throwable throwable) {
                        if (throwable instanceof IllegalArgumentException
                                && throwable.getMessage().equals("Token_refresh")) {//可自定义过期异常
                            return refreshTokenWhenTokenInvalid();//获取新的token
                        } else {
                            //其他异常可以执行退出登录操作
                            //return Observable.error(throwable);
                        }
                        return Observable.error(throwable);
                    }
                });
            }
        });
    }

    public SPUtil getSp() {
        return BaseApplication.getSp();
    }

    private Observable<?> refreshTokenWhenTokenInvalid() {
        synchronized (ProxyHandler.class) {
            if (new Date().getTime() - tokenChangedTime < REFRESH_TOKEN_VALID_TIME) {
                mIsTokenNeedRefresh = true;
                return Observable.just(true);
            } else {
                mRefreshTokenError = null;
                refresh++;
                if (refresh > 5) {
//                    ToastUtils.toastShort("登录失效,请重新登录");
                    getSp().putString(SpKeyUtils.TOKEN_ID, null);
                    getSp().putString(SpKeyUtils.LOGIN_PSW, null);
                    getSp().putString(SpKeyUtils.LOGIN_PHONE, null);
                    getSp().putString(SpKeyUtils.LOGIN_NAME, null);
                    getSp().putString(SpKeyUtils.TOKEN_ID, null);
                    launchLogin();
                }
                if (!TextUtils.isEmpty(getSp().getString(SpKeyUtils.LOGIN_NAME, null))) {
                    if (!TextUtils.isEmpty(getSp().getString(SpKeyUtils.LOGIN_PSW, null))) {
                        Log.e(TAG, "------刷新token");
                        Map<String, Object> params = new HashMap();
                        params.put("userName", getSp().getString(SpKeyUtils.LOGIN_NAME, null));
                        params.put("passWord", getSp().getString(SpKeyUtils.LOGIN_PSW, null));
                        params.put("systemCode", "keqiao_app");
                        RequestBody requestBody = RequestBody.create(MediaType.parse("application/json;charset=UTF-8"), new Gson().toJson(params));
                        HttpTokenLogin.createHttpClient().loginToken(requestBody).subscribe(new Subscriber<BaseBean<String>>() {
                            @Override
                            public void onCompleted() {
                            }

                            @Override
                            public void onError(Throwable e) {
                                Log.e(TAG, "------刷新失败");
                            }

                            @Override
                            public void onNext(BaseBean<String> responseLogin) {
                                if (responseLogin != null) {
//                                    try {
                                    mIsTokenNeedRefresh = true;
                                    tokenChangedTime = new Date().getTime();
//                                    LoginInfo info = (LoginInfo) responseLogin.getData();
                                    Log.e(TAG, "-------新token=" + responseLogin.getData());
                                    getSp().putString(SpKeyUtils.TOKEN_ID, responseLogin.getData());
//                                    } catch (UnsupportedEncodingException e) {
//                                        e.printStackTrace();
//                                    }
                                }
                            }
                        });

                    } else {
                        launchLogin();
                    }
                } else {
                    launchLogin();
                }
            }

            if (mRefreshTokenError != null) {
                return Observable.error(mRefreshTokenError);
            } else {
                return Observable.just(true);
            }
        }
    }

    private void launchLogin() {
//        ActivityCollector.finishAll();
        Intent intent = new Intent();//启动登录页面
        intent.setAction("com.keqiao.www.login");
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        BaseApplication.getInstance().startActivity(intent);
    }

    /**
     * Update the token of the args in the method.
     */
    private void updateMethodToken(Method method, Object[] args) {
        if (mIsTokenNeedRefresh && !TextUtils.isEmpty(getSp().getString(SpKeyUtils.TOKEN_ID, null))) {
            Annotation[][] annotationsArray = method.getParameterAnnotations();
            Annotation[] annotations;
            if (annotationsArray != null && annotationsArray.length > 0) {
                for (int i = 0; i < annotationsArray.length; i++) {
                    annotations = annotationsArray[i];
                    for (Annotation annotation : annotations) {
                        if (annotation instanceof Body) {
                            RequestBody requestBody = (RequestBody) args[i];
                            args[i] = getTokenRequestBody(requestBody);
                            Log.i("ProxyHandler", "----->在这里更新Body中的token");
                        }
                        if (annotation instanceof Query) {
                            if (TOKEN.equals(((Query) annotation).value())) {
                                args[i] = getSp().getString(SpKeyUtils.TOKEN_ID, null);
                                Log.i("ProxyHandler", "----->在这里更新Query中的token");
                            }
                        }
                    }
                }
            }
            mIsTokenNeedRefresh = false;
        }
    }

    public RequestBody getTokenRequestBody(RequestBody requestBody) {
        if (requestBody != null) {
            Buffer buffer = new Buffer();
            try {
                requestBody.writeTo(buffer);
                Charset charset = Charset.forName("UTF-8");
                MediaType contentType = requestBody.contentType();
                if (contentType != null) {
                    charset = contentType.charset();
                }
                String paramsStr = buffer.readString(charset);
                Map<String, Object> params = new Gson().fromJson(paramsStr, Map.class);
                params.put(TOKEN, getSp().getString(SpKeyUtils.TOKEN_ID));
                requestBody = RequestBody.create(MediaType.parse("application/json;charset=UTF-8"), new Gson().toJson(params));
            } catch (IOException e) {
                e.printStackTrace();
            }

        }
        return requestBody;
    }
}
